﻿using System;
using System.Data;
using DataScripter.Database.SqlServer;

namespace DataScripter.Database
{
    public class FieldInfo : IMetadataReader
    {
        public FieldInfo()
        { }

        public FieldInfo(string columnName, string dataType) : this(columnName, dataType, false) { }

        public FieldInfo(string columnName, string dataType, bool isIdentity)
        {
            ColumnName = columnName;
            DataType = dataType.ToUpper();
            IsIdentity = isIdentity;
        }

        #region Implementation of IMetadataReader

        public void InitializeMetadata(IDataReader reader)
        {
            ColumnName = reader.GetString("COLUMN_NAME");
            DataType = reader.GetString("DATA_TYPE").ToUpper();
            MaxLength = reader.GetNullableInt32("CHARACTER_MAXIMUM_LENGTH");
            NumericPrecision = reader.GetNullableByte("NUMERIC_PRECISION");
            NumericScale = reader.GetNullableInt32("NUMERIC_SCALE");
            IsIdentity = reader.GetBoolean("is_identity");
        }

        #endregion

        public int? NumericScale { get; set; }
        public byte? NumericPrecision { get; set; }
        public int? MaxLength { get; set; }
        public string DataType { get; set; }
        public string ColumnName { get; private set; }
        public bool IsIdentity { get; private set; }

        public string ConstructFullDataType()
        {
            switch(DataType)
            {
                case "VARCHAR":
                case "NVARCHAR":
                    return string.Format("{0}({1})", DataType, MaxLength);
                case "DECIMAL":
                    return string.Format("{0}({1},{2})", NumericPrecision, NumericScale);
                default:
                    return DataType;
            }
        }

        /// <exception cref="ArgumentOutOfRangeException"><c></c> is out of range.</exception>
        public string ReadValue(IDataReader reader)
        {
            switch (DataType)
            {
                case "TINYINT":
                    return SqlServerSyntax.ToSql(reader.GetNullableByte(ColumnName));
                case "SMALLINT":
                    return SqlServerSyntax.ToSql(reader.GetNullableInt16(ColumnName));
                case "INT":
                    return SqlServerSyntax.ToSql(reader.GetNullableInt32(ColumnName));
                case "DATETIME":
                    return SqlServerSyntax.ToSql(reader.GetNullableDateTime(ColumnName), false);
                case "FLOAT":
                    return SqlServerSyntax.ToSql(reader.GetNullableFloat(ColumnName));
                case "NVARCHAR":
                case "VARCHAR":
                    return SqlServerSyntax.ToSql(reader.GetString(ColumnName));
                case "UNIQUEIDENTIFIER":
                    return SqlServerSyntax.ToSql(reader.GetNullableGuid(ColumnName));
                case "BIT":
                    return SqlServerSyntax.ToSql(reader.GetNullableBoolean(ColumnName));
                case "DECIMAL":
                    return SqlServerSyntax.ToSql(reader.GetNullableDecimal(ColumnName));
                case "DATE":
                    return SqlServerSyntax.ToSql(reader.GetNullableDateTime(ColumnName), true);
                default:
                    throw new ArgumentOutOfRangeException("field.DataType unknown:" + DataType);
            }

        }

        public object ReadRawValue(IDataReader reader)
        {
            switch (DataType)
            {
                case "TINYINT":
                    return reader.GetNullableByte(ColumnName);
                case "SMALLINT":
                    return reader.GetNullableInt16(ColumnName);
                case "INT":
                    return reader.GetNullableInt32(ColumnName);
                case "DATETIME":
                    return reader.GetNullableDateTime(ColumnName);
                case "FLOAT":
                    return reader.GetNullableFloat(ColumnName);
                case "NVARCHAR":
                case "VARCHAR":
                    return reader.GetString(ColumnName);
                case "UNIQUEIDENTIFIER":
                    return reader.GetNullableGuid(ColumnName);
                case "BIT":
                    return reader.GetNullableBoolean(ColumnName);
                case "DECIMAL":
                    return reader.GetNullableDecimal(ColumnName);
                case "DATE":
                    return reader.GetNullableDateTime(ColumnName);
                default:
                    throw new ArgumentOutOfRangeException("field.DataType unknown:" + DataType);
            }

        }

        public override string ToString()
        {
            return ColumnName;
        }

        public static FieldInfo Guid(string columnName)
        {
            return new FieldInfo(columnName, "UNIQUEIDENTIFIER");
        }
    }
}